package com.zhenai.lancering.controller;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import android.util.Log;

import com.zhenai.lancering.model.AudioConfiguration;
import com.zhenai.lancering.ui.SpringFestivalGalaActivity;

public class AudioCapture extends Thread {
    private static final String TAG = "sync.AudioCapture";
    // Constant values:
    private static final int BUFFER_SIZE_MIN = 1024;

    // Member to interact with the parent
    private SpringFestivalGalaActivity mParent;

    // Audio capture encoding configuration
    private int mEncoding = AudioFormat.ENCODING_PCM_16BIT;

    // Audio record and configuration member objects
    private AudioRecord mAudio; // Audio recording Android class API
    private AudioConfiguration mAudioConfiguration;
    private byte[] mBuffer;    // PCM input audio buffer

    /**
     * Audio capture constructor.
     * <p>
     * Create and configure the AudioRecord object
     * *
     *
     * @throws Exception in case of any initialization failure
     */
    public AudioCapture(SpringFestivalGalaActivity parent) {
        mParent = parent;
        // Creation AudioConfiguration with the defaults configuration
        mAudioConfiguration = new AudioConfiguration();

        int status;

        // Get the input buffer minimum size
        mAudioConfiguration.mBufferSize = AudioRecord.getMinBufferSize(mAudioConfiguration.mSampleRate, mAudioConfiguration.mChannels, mEncoding);
        if (mAudioConfiguration.mBufferSize <= 0) {
            onError(1, "AudioCapture ERROR: Min buffer size must exceed 0");
        } else {
            // Check buffer size
            if (mAudioConfiguration.mBufferSize <= BUFFER_SIZE_MIN) {
                mAudioConfiguration.mBufferSize = BUFFER_SIZE_MIN * mAudioConfiguration.mChannels;
            }
        }

        // Audio recording initialization
        mBuffer = new byte[mAudioConfiguration.mBufferSize];
        mAudio = new AudioRecord(AudioSource.MIC, mAudioConfiguration.mSampleRate, mAudioConfiguration.mChannels, mEncoding, mAudioConfiguration.mBufferSize);
        status = mAudio.getState();
        if (status == AudioRecord.STATE_INITIALIZED) {
            // Start the audio recording
            mAudio.startRecording();
        } else {
            onError(2, "Expected state=STATE_INITIALIZED, current state=" + status);
        }
    }

    /**
     * Audio Capture.
     * <p>
     * Stop thread
     */
    public void finalize() {
        try {
            if (null != mAudio) {
                mAudio.stop();
                mAudio.release();
                mAudio = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Audio configuration.
     * <p>
     * Getter AudioConfiguration
     */
    public AudioConfiguration getAudioConfiguration() {
        return mAudioConfiguration;
    }


    /**
     * Audio capture thread entry point.
     * <p>
     * This worker thread reads audio buffers from microphone and provides the audio samples to the SDK stack.
     * <p>
     * The thread terminates when interrupted or when an error occurred.
     */
    public void run() {
        int status;
        try {
            while (!isInterrupted()) {
                if (mAudioConfiguration.mBufferSize > 0) {
                    status = mAudio.read(mBuffer, 0, mAudioConfiguration.mBufferSize);
                    if ((0 == status) || (AudioRecord.ERROR_INVALID_OPERATION == status)) {
                        // The mic resource may be already in use by another App..
                        // In some devices ERROR_INVALID_OPERATION is returned, in others 0 is returned..
                        onError(3, "mic resource already in use - ERROR_INVALID_OPERATION");
                    } else if (AudioRecord.ERROR_BAD_VALUE == status) {
                        onError(4, "mic resource already in use - ERROR_BAD_VALUE");
                    } else {
                        if (null != mParent && !mParent.pushAudioBuffer(mBuffer, mAudioConfiguration.mBufferSize)) {
                            onError(5, "pushAudioBuffer()=false");
                        }
                    }
                }
            }
        } catch (Exception e) {
            onError(6, "Exceptions in audio loop - msg=" + e.getMessage());
        }
    }

    public void onError(int code, String msg) {
        Log.e(TAG, "code:" + code + ",msg:" + msg);
    }
}
